#include "net_pre.h"
#include "inet_session.h"
#include "common.h"

namespace Net
{
	INetSession::INetSession(boost::asio::io_service& io_service)
		: socket_(io_service)
	{
		memset(read_buffers_[0], 0, PacketHeader::PACKET_MAX_SIZE);
		memset(read_buffers_[1], 0, PacketHeader::PACKET_MAX_SIZE);
		read_buffer_remain_length_ = 0;
		state_ = STATE_CONNECT;
	}

	INetSession::~INetSession()
	{
		Close();
	}

	boost::asio::ip::tcp::socket& INetSession::GetSocket()
	{
		return socket_;
	}

	std::string INetSession::GetRemoteIp()
	{
		boost::system::error_code ec;
		socket_.remote_endpoint(ec);
		if (!ec)
			socket_.remote_endpoint().address().to_string();
		return "";
	}

	void INetSession::Start()
	{
		if (state_ == STATE_CONNECT)
		{
			state_ = STATE_HANDSHAKE;
			PacketHeader header;
			Send(&header);
			if (cur_send_count_ == 0)
				socket_.get_io_service().post(boost::bind(&INetSession::SendImp, shared_from_this()));
			state_ = STATE_RUNNING;

			socket_.async_read_some(boost::asio::buffer(read_buffers_[0], PacketHeader::PACKET_MAX_SIZE),
				boost::bind(&INetSession::ReadHandle, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, read_buffers_[0], read_buffers_[1]));

			if (connect_callback_)
				connect_callback_();
		}
	}

	void INetSession::Close()
	{
		socket_.close();
		state_ = STATE_CLOSE;
	}

	void INetSession::Send(PacketHeader* packet)
	{
		if (!packet)
		{
			//error
			Close();
			return;
		}

		if (packet->packet_size_ > PacketHeader::PACKET_MAX_SIZE)
		{
			//error
			Close();
			return;
		}

		IoBuffer* buffer = GetFrontIoBuffer();
		if (!buffer)
		{
			buffer = new IoBuffer();
			PushIoBuffer(buffer);
		}
		else
		{
			if (buffer->get_rest_size()<packet->packet_size_)
			{
				buffer = new IoBuffer();
				PushIoBuffer(buffer);
			}
		}

		if (!buffer->write_data((char*)packet,packet->packet_size_))
		{
			//error
			Close();
			return;
		}

		if (cur_send_count_ == 0)
			socket_.get_io_service().post(boost::bind(&INetSession::SendImp, shared_from_this()));
	}

	IoBuffer* INetSession::GetFrontIoBuffer()
	{
		if (send_buffer_queue_.empty())
			return NULL;
		return send_buffer_queue_.front();
	}

	void INetSession::PushIoBuffer(IoBuffer* buffer)
	{
		send_buffer_queue_.push(buffer);
	}

	void INetSession::SendImp()
	{
		if ( !send_buffer_queue_.empty() )
		{
			IoBuffer* buffer = send_buffer_queue_.front();
			boost::asio::async_write(socket_, boost::asio::buffer(buffer,PacketHeader::PACKET_MAX_SIZE),
				boost::bind(&INetSession::WriteHandle, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, buffer));
			send_buffer_queue_.pop();
			cur_send_count_++;
		}
	}

	void INetSession::WriteHandle(boost::system::error_code ec, std::size_t transfer_length, IoBuffer* data)
	{
		if (ec)
		{
			//outlog
			Close();
			return;
		}

		transfer_length;
		SAFE_DELETE(data);
		cur_send_count_--;

		SendImp();
	}

	void INetSession::ReadHandle(boost::system::error_code ec, std::size_t transfer_length, char* rb0, char* rb1)
	{
		if (ec)
		{
			//outlog
			Close();
			return;
		}

		PacketHeader* header = (PacketHeader*)rb0;
		read_buffer_remain_length_ += (int)transfer_length;

		if (read_buffer_remain_length_ >= PacketHeader::PACKET_HEAD_SIZE)
		{
			while (read_buffer_remain_length_ >= header->packet_size_)
			{
				read_buffer_remain_length_ -= header->packet_size_;
				if (header->packet_size_ > PacketHeader::PACKET_MAX_SIZE || header->packet_size_ < PacketHeader::PACKET_HEAD_SIZE)
				{
					//error;
					Close();
					return;
				}
				else if (header->packet_size_ == PacketHeader::PACKET_HEAD_SIZE)
				{
					//ping
				}
				else
				{
					if (receive_callback_) 
						receive_callback_((char*)header, NULL);
				}

				if (read_buffer_remain_length_ >= PacketHeader::PACKET_HEAD_SIZE)
					header = (PacketHeader*)(rb0 + PacketHeader::PACKET_MAX_SIZE - read_buffer_remain_length_);
				else
					break;
			}
		}

		if (read_buffer_remain_length_ > 0)
			memcpy(rb1, rb0 + PacketHeader::PACKET_MAX_SIZE - read_buffer_remain_length_, read_buffer_remain_length_);

		socket_.async_read_some(boost::asio::buffer(rb1 + read_buffer_remain_length_, PacketHeader::PACKET_MAX_SIZE - read_buffer_remain_length_),
			boost::bind(&INetSession::ReadHandle, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, rb1, rb0));
	}
}